"""
Generic command module. Pretty much every command should go here for
now.
"""
import time
from django.conf import settings
from src.server.sessionhandler import SESSIONS
from src.utils import utils, search
from src.objects.models import ObjectNick as Nick
from src.commands.default.muxcommand import MuxCommand, MuxCommandOOC
from game.gamesrc.commands.command import MyCommand

# limit symbol import for API
__all__ = ("CmdHome", "CmdLook", "CmdPassword", "CmdNick",
           "CmdInventory", "CmdGet", "CmdDrop", "CmdQuit", "CmdWho",
           "CmdSay", "CmdPose", "CmdEncoding", "CmdAccess",
           "CmdOOCLook", "CmdIC", "CmdOOC")

AT_SEARCH_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS

class MyCmdLook(MuxCommand):
    """
    look

    Usage:
      look
      look <obj>
      look *<player>

    Observes your location or objects in your vicinity.
    """
    key = "look"
    aliases = ["l", "ls"]
    locks = "cmd:all()"
    arg_regex = r"\s.*?|$"

    def func(self):
        """
        Handle the looking.
        """
        caller = self.caller
        args = self.args
        if args:
            # Use search to handle duplicate/nonexistant results.
            looking_at_obj = caller.search(args, use_nicks=True)
            if not looking_at_obj:
                return
        else:
            looking_at_obj = caller.location
            if not looking_at_obj:
                caller.msg("Non hai nulla da guardare!")
                return

        if not hasattr(looking_at_obj, 'return_appearance'):
            # this is likely due to us having a player instead
            looking_at_obj = looking_at_obj.character
        if args: args = " %s" % args
        if 'WILD' in self.caller.location.flags:
            if not looking_at_obj.access(caller, "view", caller.wild_loc):
                caller.msg("Non riesci a vedere%s." % args)
                return
        if not looking_at_obj.access(caller, "view"):

            caller.msg("Non riesci a vedere%s." % args)
            return
        # get object's appearance
        caller.msg(looking_at_obj.return_appearance(caller))
        if looking_at_obj != caller and (looking_at_obj.has_player or 'MOB' in looking_at_obj.flags):
           looking_at_obj.msg("%s ti guarda." % caller.name.capitalize())
           caller.location.msg_contents("%s guarda %s", obj_list=[caller, looking_at_obj],
                                                        exclude=[caller, looking_at_obj],
                                                        wild_loc=caller.db.wild_loc)
        # the object's at_desc() method.
        looking_at_obj.at_desc(looker=caller)

class MyCmdInventory(MuxCommand):
    """
    inventory

    Usage:
      inventory
      inv

    Shows your inventory.
    """
    key = "inventory"
    aliases = ["inv", "i"]
    locks = "cmd:all()"

    def func(self):
        "check inventory"
        items = self.caller.contents
        items = filter(lambda x: x not in self.caller.equip.values(), items)
        if not items:
            string = "Non stai trasportando niente."
        else:
            # format item list into nice columns
            cols = [[],[]]
            for item in items:
                cols[0].append(item.name.capitalize())
                desc = item.db.desc
                if not desc:
                    desc = ""
                cols[1].append(utils.crop(str(desc)))
            # auto-format the columns to make them evenly wide
            ftable = utils.format_table(cols)
            string = "Stai portando:"
            for row in ftable:
                string += "\n " + "{C%s{n - %s" % (row[0], row[1])
        self.caller.msg(string)

class MyCmdGet(MyCommand):
    """
    get

    Usage:
      get <obj>
      get all
      get <obj>.<index>
      get <obj>.all

      get <obj> <container>
      get all <container>
      get <obj>.<index> <container>
      get <obj>.all <container>

    Picks up one or more objects from your location and puts it in
    your inventory.
    Only supports aliases, to get objects by object name you can use 
    underscore instead of space ("get A_knife" it's ok but not " get A knife")

    """
    key = "get"
    aliases = "grab, take, prendi"
    locks = "cmd:all()"

    def func(self):
        "implements the command."

        caller = self.caller
        args = self.args
        if not args:
            caller.msg("Prendere cosa?")
            return

        n = 1
        if args[0][1].isdigit():
            n = int(args.pop(0)[1])

        source = None

        # this will search for containers as source for objects,
        # if not specified the source will be current location        
        if len(args) > 1:
            index, string = args[1] 
            if (string == "all" or index == ".all"):
                caller.msg("Non puoi!")
                return
            try:
                source = self.get_objects_from_string(index, string, [caller, caller.location])[0]
            except IndexError:
                pass

            if not source:
                caller.msg("Da dove?")
                return           

            if not 'CONTAINER' in source.flags:
                caller.msg("Ma non e' un contenitore!")
                return

            if hasattr(source, "is_closed") and source.db.is_closed:
                caller.msg("Dovresti aprirlo prima di riuscire a prendere qualcosa da li'!")
                return

        if not source:
            candidates = caller.location
        else:
            candidates = source


        index, string = args[0]

        objs = self.get_objects_from_string(index, string, candidates, n)

       # don't take weird stuff when taking multiple objects
        if len(objs) > 1:
            objs = [element for element in objs if (element.access(caller, 'get') 
                                             and not element.location == caller)]
        if not objs:
            caller.msg("Che cosa vuoi prendere?")
            return

        for element in objs:
            if element.location == caller:
                caller.msg("Hai gia' quell'oggetto nell'inventario.")
                continue

            if caller == element:
                caller.msg("Non puoi prendere te stesso!")
                continue

            if not element.access(caller, 'get'):
                if element.db.get_err_msg:
                    caller.msg(obj.db.get_err_msg)
                else:
                    caller.msg("Non puoi prenderlo.")
                continue

            element.move_to(caller, quiet=True)

            src = ""
            if source:
                caller.msg("Hai preso %s da %s.", obj_list=[element, source])
                caller.location.msg_contents("%s prende %s da %s.", obj_list=[caller, element, source],
                                                                    exclude=caller,
                                                                    wild_loc=caller.wild_loc)
            else:
                caller.msg("Hai preso %s.", obj_list=[element])
                caller.location.msg_contents("%s prende %s.", obj_list=[caller, element], 
                                                              exclude=caller,
                                                              wild_loc=caller.wild_loc)

            # calling hook method
            element.at_get(caller)



class MyCmdDrop(MyCommand):
    """
    drop

    Usage:
      drop <obj>

    Lets you drop an object from your inventory into the
    location you are currently in.
    """

    key = "drop"
    aliases = "posa"
    locks = "cmd:all()"

    def func(self):
        "Implement command"

        caller = self.caller
        args = self.args

        if not args:
            caller.msg("Che cosa vorresti posare?")
            return

        n = 1
        if args[0][1].isdigit():
            n = int(args.pop(0)[1])

        index, string = args[0]        

        objs = self.get_objects_from_string(index, string, caller, n)

        if not objs:
            caller.msg("Che cosa vuoi posare?")
            return

        for obj in objs:
            if obj in caller.db.equip.values():
                caller.msg("Non puoi posare un oggetto equipaggiato.")
                continue
            obj.move_to(caller.location, quiet=True, wild_loc=caller.db.wild_loc)
            caller.msg("Hai posato %s." % (obj.name,))
            caller.location.msg_contents("%s posa %s.", exclude=caller, obj_list=[caller, obj], wild_loc=caller.wild_loc)
            # Call the object script's at_drop() method.
            obj.at_drop(caller)



